var NP = (function(exports) {
    'use strict';

    /**
     * @file 解决浮动运算问题，避免小数点后产生多位数和计算精度损失。
     * 问题示例：2.3 + 2.4 = 4.699999999999999，1.0 - 0.9 = 0.09999999999999998
     */
    /**
     * 把错误的数据转正
     * strip(0.09999999999999998)=0.1
     */
    function strip(num, precision) {
        if (precision === void 0) {
            precision = 12;
        }
        return +parseFloat(num.toPrecision(precision));
    }
    /**
     * Return digits length of a number
     * @param {*number} num Input number
     */
    function digitLength(num) {
        // Get digit length of e
        var eSplit = num.toString().split(/[eE]/);
        var len = (eSplit[0].split('.')[1] || '').length - (+(eSplit[1] || 0));
        return len > 0 ? len : 0;
    }
    /**
     * 把小数转成整数，支持科学计数法。如果是小数则放大成整数
     * @param {*number} num 输入数
     */
    function float2Fixed(num) {
        if (num.toString().indexOf('e') === -1) {
            return Number(num.toString().replace('.', ''));
        }
        var dLen = digitLength(num);
        return dLen > 0 ? num * Math.pow(10, dLen) : num;
    }
    /**
     * 检测数字是否越界，如果越界给出提示
     * @param {*number} num 输入数
     */
    function checkBoundary(num) {
        if (num > Number.MAX_SAFE_INTEGER || num < Number.MIN_SAFE_INTEGER) {
            console.warn(num + " is beyond boundary when transfer to integer, the results may not be accurate");
        }
    }
    /**
     * 精确乘法
     */
    function times(num1, num2) {
        var others = [];
        for (var _i = 2; _i < arguments.length; _i++) {
            others[_i - 2] = arguments[_i];
        }
        if (others.length > 0) {
            return times.apply(void 0, [times(num1, num2), others[0]].concat(others.slice(1)));
        }
        var num1Changed = float2Fixed(num1);
        var num2Changed = float2Fixed(num2);
        var baseNum = digitLength(num1) + digitLength(num2);
        var leftValue = num1Changed * num2Changed;
        checkBoundary(leftValue);
        return leftValue / Math.pow(10, baseNum);
    }
    /**
     * 精确加法
     */
    function plus(num1, num2) {
        var others = [];
        for (var _i = 2; _i < arguments.length; _i++) {
            others[_i - 2] = arguments[_i];
        }
        if (others.length > 0) {
            return plus.apply(void 0, [plus(num1, num2), others[0]].concat(others.slice(1)));
        }
        var baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2)));
        return (times(num1, baseNum) + times(num2, baseNum)) / baseNum;
    }
    /**
     * 精确减法
     */
    function minus(num1, num2) {
        var others = [];
        for (var _i = 2; _i < arguments.length; _i++) {
            others[_i - 2] = arguments[_i];
        }
        if (others.length > 0) {
            return minus.apply(void 0, [minus(num1, num2), others[0]].concat(others.slice(1)));
        }
        var baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2)));
        return (times(num1, baseNum) - times(num2, baseNum)) / baseNum;
    }
    /**
     * 精确除法
     */
    function divide(num1, num2) {
        var others = [];
        for (var _i = 2; _i < arguments.length; _i++) {
            others[_i - 2] = arguments[_i];
        }
        if (others.length > 0) {
            return divide.apply(void 0, [divide(num1, num2), others[0]].concat(others.slice(1)));
        }
        var num1Changed = float2Fixed(num1);
        var num2Changed = float2Fixed(num2);
        checkBoundary(num1Changed);
        checkBoundary(num2Changed);
        return times((num1Changed / num2Changed), Math.pow(10, digitLength(num2) - digitLength(num1)));
    }
    /**
     * 四舍五入
     */
    function round(num, ratio) {
        var base = Math.pow(10, ratio);
        return divide(Math.round(times(num, base)), base);
    }

    // eval 计算公式; CalcEval('(0.2+0.1)/2+(0.1+0.2)-(10)')
    function CalcEval(str) {
        var isRetStr = str.match(new RegExp(/^".+"$/g)) != null;
        if (isRetStr == true) {
            str = str.replace(/^"|"$/g, "")
        }
        var bracketsList = matchOutBrackets(str);
        for (var i = 0; i < bracketsList.length; i++) {
            var newCalc = bracketsList[i];
            var calcStr = CalcEval(newCalc.str.replace(/^\(|\)$/g, ""));
            str = str.replace(newCalc.str, calcStr)
        }
        var errorObj = new Array();
        while (1) {
            var multObj = matchExp(str, "/");
            if (multObj == null) {
                break
            }
            var v = divide(multObj.firstValue, multObj.secondValue);
            if (v == "NaN") {
                var t = "T" + new Date().getTime();
                errorObj.push({
                    Name: t,
                    Exp: multObj.str
                });
                str = str.replace(multObj.str, t)
            } else {
                str = str.replace(multObj.str, v)
            }
        }
        while (1) {
            var multObj = matchExp(str, "*");
            if (multObj == null) {
                break
            }
            var v = times(multObj.firstValue, multObj.secondValue);
            if (v == "NaN") {
                var t = "T" + new Date().getTime();
                errorObj.push({
                    Name: t,
                    Exp: multObj.str
                });
                str = str.replace(multObj.str, t)
            } else {
                str = str.replace(multObj.str, v)
            }
        }
        while (1) {
            var multObj = matchExp(str, "+");
            if (multObj == null) {
                break
            }
            var v = plus(multObj.firstValue, multObj.secondValue);
            if (v == "NaN" || isNaN(v)) {
                var t = "T" + new Date().getTime();
                errorObj.push({
                    Name: t,
                    Exp: multObj.str
                });
                str = str.replace(multObj.str, t)
            } else {
                str = str.replace(multObj.str, v)
            }
        }
        while (1) {
            var multObj = matchExp(str, "-");
            if (multObj == null) {
                break
            }
            var v = minus(multObj.firstValue, multObj.secondValue);
            if (v == "NaN") {
                var t = "T" + new Date().getTime();
                errorObj.push({
                    Name: t,
                    Exp: multObj.str
                });
                str = str.replace(multObj.str, t)
            } else {
                str = str.replace(multObj.str, v)
            }
        }
        for (var i = errorObj.length - 1; i >= 0; i--) {
            var ex = errorObj[i];
            str = str.replace(ex.Name, ex.Exp)
        }
        while (1) {
            var multObj = str.match(/\d*={2,3}\d*/g);
            if (multObj == null) {
                break
            }
            var v = eval(multObj[0]);
            str = str.replace(multObj[0], v)
        }
        if (isRetStr == true) {
            try {
                return eval('"' + str + '"')
            } catch (e) {}
            try {
                return eval(str)
            } catch (e) {}
            return str
        }
        if (str.match(/(^true$)|(^false$)/g)) {
            return str === "true"
        }
        if (!isNaN(Number(str))) {
            return Number(str)
        }
        try {
            return eval(str)
        } catch (e) {}
        return str
    }

    // 匹配括号
    function matchOutBrackets(f) {
        var h = new Array();
        if (f == null) {
            return h
        }
        if (typeof f != "string") {
            f = f + ""
        }
        var d = f.split("");
        var a = 0;
        var g = false;
        var b = -1;
        for (var c = 0; c < d.length; c++) {
            if (d[c] == "(") {
                a++;
                g = true;
                if (b == -1) {
                    b = c
                }
            }
            if (d[c] == ")") {
                a--
            }
            if (g == true && a == 0) {
                var e = new Object();
                e.str = f.substring(b, c + 1);
                e.firstIndex = b;
                e.lastIndex = c + 1;
                h.push(e);
                b = -1;
                g = false;
                a = 0
            }
        }
        return h
    }

    // 匹配加减乘除
    function matchExp(l, f) {
        var j = null;
        if (l == null) {
            return retList
        }
        if (typeof l != "string") {
            l = l + ""
        }
        var k = l.split("");
        var c = 0;
        var b = 0;
        var g = "";
        var e = "";
        var a = "";
        var d = false;
        for (var h = 0; h <= k.length; h++) {
            if (k[h] == "+" || k[h] == "-" || k[h] == "*" || k[h] == "/" || k[h] == "%" || h == k.length) {
                if (a == "" && k[h] == "-") {
                    a += k[h];
                    continue
                }
                if (d == true) {
                    e = a;
                    b = h;
                    j = new Object();
                    j.firstIndex = c;
                    j.secondIndex = b;
                    j.str = l.substring(c, b);
                    j.firstValue = Number(g);
                    j.secondValue = Number(e);
                    break
                }
                if (k[h] == null) {
                    break
                }
                if (k[h] == f) {
                    d = true;
                    g = a;
                    a = ""
                } else {
                    a = "";
                    c = -1
                }
            } else {
                a += k[h];
                if (c == -1) {
                    c = h
                }
            }
        }
        return j
    }


    var index = {
        strip: strip,
        plus: plus,
        minus: minus,
        times: times,
        divide: divide,
        round: round,
        digitLength: digitLength,
        float2Fixed: float2Fixed,
        CalcEval: CalcEval
    };

    exports.strip = strip;
    exports.plus = plus;
    exports.minus = minus;
    exports.times = times;
    exports.divide = divide;
    exports.round = round;
    exports.digitLength = digitLength;
    exports.float2Fixed = float2Fixed;
    exports.CalcEval = CalcEval;
    exports['default'] = index;

    return exports;

}({}));